package com.ship.contract.task;

import com.ship.common.core.base.BaseBean;
import com.ship.common.core.base.ContractBaseBean;
import com.ship.common.core.base.Page;
import com.ship.common.core.domain.R;
import com.ship.common.core.exception.BusException;
import com.ship.common.core.mapping.Label;
import com.ship.common.business.service.BaseService;
import com.ship.contract.service.ExportService;
import com.ship.common.core.task.ExportTask;
import com.ship.common.core.utils.FieldUtil;
import com.ship.common.core.utils.MethodUtil;
import com.ship.common.core.utils.ZipUtils;
import com.ship.common.core.web.domain.BaseResultCode;
import com.ship.contract.bean.ConFiles;
import com.ship.contract.service.ConFilesService;
import com.ship.contract.service.TableConfigService;
import com.ship.system.api.RemoteFileService;
import com.ship.common.core.utils.bean.SysFile;
import lombok.Data;
import ognl.Ognl;
import ognl.OgnlException;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * @author tangshixuan
 * @date 2023-9-7
 */
@Data
public class ExportContractDataTask extends ExportTask implements Serializable{

    private static final long serialVersionUID = 6061088309079176767L;
    private String module;
    private Method method;
    private String methodsName;
    private BaseService baseService;
    private ContractBaseBean baseBean;
    private Long userId;

    @Resource
    private RemoteFileService remoteFileService;

    @Override
    public void run() {
        List<Long> ids = baseBean.getIds();
        List<ContractBaseBean> data = new ArrayList<>();
        //获取需要导出的数据
        if(ids == null || ids.isEmpty()){
            data = getDataByMethods();
        }else{
            data = getDataByIds(ids);
        }

        data = data.stream()
                .filter(item -> {
                    try {
                        Field field = item.getClass().getDeclaredField("delApply");
                        field.setAccessible(true);
                        Integer value = (Integer) field.get(item);
                        return value == null || !value.equals(2);
                    } catch (Exception e) {
                        e.printStackTrace();
                        return true; // 出现异常时保留该项
                    }
                })
                .collect(Collectors.toList());
        //压缩包文件夹
        String zipFolderPath = System.getProperty("java.io.tmpdir") + File.separator + UUID.randomUUID().toString();
        File zipFolder = new File(zipFolderPath);
        if(!zipFolder.exists()){
            zipFolder.mkdirs();
        }
        //处理表格数据
        handleExcel(data,zipFolderPath);
        //处理合同文件
        handleContractFiles(data,zipFolderPath);

        String zipFilePath = zipFolderPath + ".zip";
        File zipFile = new File(zipFilePath);
        try {
            FileOutputStream fos1 = new FileOutputStream(zipFile);
            ZipUtils.toZip(zipFolderPath,fos1,false);

            FileInputStream fileInputStream = new FileInputStream(zipFile);
            MultipartFile file = new MockMultipartFile(zipFile.getName(), zipFile.getName(), null, fileInputStream);

//            R<SysFile> result = remoteFileService.upload(file);
            R<SysFile> result = getHttpRequestUtil().upload(file);
            if(result.getCode() == R.SUCCESS){
                String path = result.getData().getHttpsUrl();
                ((ExportService)getSpringUtil().getBean(ExportService.class)).finish(getExportId(), zipFile,path);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //删除表格文件
        zipFolder.delete();
        zipFile.delete();
    }

    private void handleContractFiles(List<ContractBaseBean> data, String zipFolderPath) {

        for(ContractBaseBean bean: data){
            Long id = bean.getId();
            //合同名称
            String contractName = bean.getContractName();
            ConFiles conFile = getContractFile(id);
            if(conFile == null){
                continue;
            }
            String fileUrl = conFile.getUrl();
            //拼接合同文件地址
//            String outputFilePath = zipFolderPath + File.separator + contractName + fileUrl.substring(fileUrl.lastIndexOf("."),fileUrl.length());
            String outputFilePath;
            int lastDotIndex = fileUrl.lastIndexOf(".");
            if (lastDotIndex != -1) {
                outputFilePath = zipFolderPath + File.separator + contractName + fileUrl.substring(lastDotIndex, fileUrl.length());
            } else {
                outputFilePath = zipFolderPath + File.separator + contractName + ".defaultExtension";
            }
            try {
//        URL url = new URL(fileUrl);
//        URLConnection conn = url.openConnection();
//        InputStream inputStream = conn.getInputStream();
                File file = new File(fileUrl);
                FileInputStream input = new FileInputStream(file);
                MultipartFile multipartFile = new MockMultipartFile("file", file.getName(), "application/octet-stream", input);
                R<com.ship.system.api.domain.SysFile> result1 = remoteFileService.upload(multipartFile);
                if(result1.getCode() != R.SUCCESS){
                    throw new BusException("文件服务器连接失败", BaseResultCode.GENERAL_ERROR);
                }
                String url = result1.getData().getHttpsUrl();
                OutputStream outputStream = new FileOutputStream(outputFilePath);
                byte[] buffer = new byte[4096];
                int bytesRead;
                while ((bytesRead = input.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }
                outputStream.close();
                input.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private ConFiles getContractFile(Long id) {
        return ((ConFilesService)getSpringUtil().getBean(ConFilesService.class)).getContractMainFile(id);
    }

    private void handleExcel(List<ContractBaseBean> data,String zipFolderPath) {
        //表格数据
        String excelFilePath = zipFolderPath + File.separator + getDownloadFileName().replace(".zip","") + ".xlsx";
        File file = new File(excelFilePath);
        //获取类所有列
        List<Field> fields = FieldUtil.getAllFields(baseBean.getClass());
        //获取类需要导出的列
        List<String> columns = getExportColumns();
        XSSFWorkbook workbook = null;
        XSSFSheet sheet = null;
        XSSFRow header = null;
        try {
            workbook = new XSSFWorkbook();
            sheet = workbook.createSheet();
            header = sheet.createRow(0);
        } catch (Exception e) {
            return;
        }
        List<String> fieldsStr = new ArrayList<String>();
        for (Field field : fields) {
            String columnName = field.getName();
            //只导出配置的列
            if(columns.contains(columnName)){
                Label label = field.getAnnotation(Label.class);
                if(label != null && label.notExport() == false) {
                    fieldsStr.add(field.getName());
                    XSSFCell cell = header.createCell(fieldsStr.size() - 1);
                    cell.setCellValue(label.value()[0]);
                }
            }
        }
        int rowIndex = 1;
        for (BaseBean bean: data) {
            int index = 0;
            XSSFRow row = sheet.createRow(rowIndex);
            for (String field : fieldsStr) {
                Object value = null;
                try {
                    value = Ognl.getValue(field, bean);
                }catch (OgnlException e){
                    e.printStackTrace();
                }
                if(value == null) {
                    value = "";
                }
                if (value instanceof Double || value instanceof Long || value instanceof Integer || value instanceof BigDecimal){
                    row.createCell(index).setCellValue(Double.valueOf(String.valueOf(value)));
                }else {
                    row.createCell(index).setCellValue(value.toString());
                }

                index ++;
            }
            rowIndex ++;
        }
        try {
            workbook.write(new FileOutputStream(file));
            workbook.close();
        } catch (IOException e) {
            return;
        }
    }

    private List<String> getExportColumns() {
        return ((TableConfigService)getSpringUtil().getBean(TableConfigService.class)).listStrByModuleAndUser(module,userId);
    }

    private List<ContractBaseBean> getDataByIds(List<Long> ids) {
        return baseService.listByIds(ids);
    }

    private List<ContractBaseBean> getDataByMethods() {
        Method method = null;
        Class<?> superClass = baseService.getClass();
        for (Method methodTmp : MethodUtil.getAllMethod(superClass)) {
            if(methodTmp.getParameterCount() == 1 && methodTmp.getName().equals(methodsName)) {
                Class<?> paramClass = methodTmp.getParameters()[0].getType();
                if(paramClass.isAssignableFrom(baseBean.getClass())) {
                    method = methodTmp;
                    break;
                }
            }
        }
        if(method == null) {
            throw new BusException("导出任务建立失败：" + baseService.getClass().getName() + " 中不存在方法 " + methodsName, BaseResultCode.GENERAL_ERROR);
        }
        baseBean.setPageSize(Integer.MAX_VALUE);
        baseBean.setPageNum(1);
        try {
            return ((Page<ContractBaseBean>) method.invoke(baseService, new Object[] {baseBean})).getList();
        } catch (Exception e) {
            return new ArrayList<ContractBaseBean>();
        }
    }
}
